﻿package com.gobang.aimode.aiengine;

import java.util.List;
import java.util.Stack;

import com.gobang.gobangui.MainWindowUI;
import com.gobang.util.chessdata.ChessPoint;
import com.gobang.util.playeraction.CommonAction;

public class GoBangAI {

	final static int N = 15, BLACK = 1, WHITE = 2;
	private int maxDepth;
	private int computerRole;
	private ChessPoint optimumChessPoint;
	private int[][] forecastChessboard = new int[16][16];
	private Stack<ChessPoint> chessStack = new Stack<ChessPoint>();
	private long duration;
	private long totalNode;

	public ChessPoint getOptimumChessPoint() {
		return optimumChessPoint;
	}
	
	public long getDuration() {
		return duration;
	}
	
	public GoBangAI(int depth, int[][] forecastChessboard) {
		long start = System.currentTimeMillis();
		chessStack = (Stack<ChessPoint>) MainWindowUI.getLocalPlayFrame().getChessStack().clone();
		if (chessStack.isEmpty()) {
			optimumChessPoint = new ChessPoint((N + 1)/2, (N + 1)/2, BLACK);
			return;
		}
		this.forecastChessboard = forecastChessboard.clone();
		computerRole = MainWindowUI.getLocalPlayFrame().getComputerRole();
		maxDepth = MainWindowUI.getLocalPlayFrame().getMaxDepth();
		Alpha(depth, 999999);
		duration = System.currentTimeMillis() - start;
		System.out.println("Step:" + (chessStack.size() + 1) + "\tTime:" + duration + "\tNode: " + totalNode);
	}

	public int Alpha(int depth, int beta) {
		totalNode++;
		if (depth == 0) {
			Evaluate evaluate = new Evaluate(forecastChessboard, chessStack, computerRole);
			int Weigh = evaluate.complexionWeigh();
//			for(int o = 0; o < (maxDepth - depth)*2; o++)
//				System.out.print(" ");
//			System.out.println("Alpha depth:" + depth + ":return:" + Weigh);
			return Weigh - (maxDepth - depth)*100;
		}
		CreatePossibleMove createPossibleMove = 
				new CreatePossibleMove(forecastChessboard, chessStack, computerRole);
		List<ChessPoint> possibleMove = createPossibleMove.getPossibleMoveList();
		
		if (possibleMove.isEmpty()) {
			return -99999;
		}
		int alpha = -9999999;
		for (ChessPoint chessPoint : possibleMove) {
			MakeNextMove(chessPoint, depth);
			int value;
			if (CommonAction.CheckWin(chessPoint.getX(), chessPoint.getY(), 
					chessPoint.getNowPlay(), forecastChessboard) != null) {
				
				if (depth == maxDepth) {
					optimumChessPoint = chessPoint;
				}
				
				UnmakeMove(chessPoint, depth);
				return 999999;
			}
			value = Beta(depth - 1, alpha);
			UnmakeMove(chessPoint, depth);
			if (value > beta) {
				return value;
			}
			if (value > alpha){
				alpha = value;
				if (depth == maxDepth) {
					optimumChessPoint = chessPoint;					
				}
			}
		}
		return alpha;
	}

	public int Beta(int depth, int alpha) {
		totalNode++;
		if (depth == 0) {
			Evaluate evaluate = new Evaluate(forecastChessboard, chessStack, 3 - computerRole);
			int Weigh = evaluate.complexionWeigh();
			
//			for(int o = 0; o < (maxDepth - depth)*2; o++)
//				System.out.print(" ");
//			System.out.println("Beta depth:" + depth + ":return:" + Weigh);
			
			return Weigh - (maxDepth - depth)*100;
		}
		CreatePossibleMove createPossibleMove = 
				new CreatePossibleMove(forecastChessboard, chessStack, 3 - computerRole);
		List<ChessPoint> possibleMove = createPossibleMove.getPossibleMoveList();
		
		/*********测试**********/
//		for(int o = 0; o < (maxDepth - depth)*2; o++)
//			System.out.print(" ");
//		System.out.println("Beta depth:" + depth);
//		for(int o = 0; o < (maxDepth - depth)*2; o++)
//			System.out.print(" ");
//		for (ChessPoint is : possibleMove) {
//			System.out.print(is.getX() + ":" + is.getY() + "=" + is.getSore() + " ");
//		}
//		System.out.println("");
		/*********测试**********/
		
		if (possibleMove.isEmpty()) {
			System.out.println("走法产生为0");
			return 99999;
		}
		int beta = 9999999;
		for (ChessPoint chessPoint : possibleMove) {
			MakeNextMove(chessPoint, depth);
			int value;
			if (CommonAction.CheckWin(chessPoint.getX(), chessPoint.getY(), 
					chessPoint.getNowPlay(), forecastChessboard) != null) {
				
//				for (int j = 1; j <= 15; j++) {
//					for (int i = 1; i <= 15; i++) {
//						switch (forecastChessboard[i][j]) {
//						case 1 :System.out.print(" ● ");break;
//						case 2: System.out.print(" ○ ");break;
//						default : System.out.print("【】");break;
//						}
//					}
//					System.out.println("");
//				}
//				System.out.println("预测有赢，该节点搜索结束");
				
				UnmakeMove(chessPoint, depth);
				return -999999;
			}
			value = Alpha(depth - 1, beta);
			UnmakeMove(chessPoint, depth);
			if (value < alpha) {
				return value;
			}
			if (value < beta){
				beta = value;
				
//				for(int o = 0; o < (maxDepth - depth)*2; o++)
//					System.out.print(" ");
//				System.out.println(depth + "beta暂时下棋点*************************************" 
//						+ chessPoint.getX() + ":" + chessPoint.getY() + "=" + beta + " ");
			}
		}
		return beta;
	}

	public void MakeNextMove(ChessPoint chessPoint, int depth) {
		chessStack.push(chessPoint);
		forecastChessboard[chessPoint.getX()][chessPoint.getY()] = chessPoint.getNowPlay();
		
//		for(int o = 0; o < (maxDepth - depth)*2; o++)
//			System.out.print(" ");
//		System.out.println(depth + "下子：" + chessPoint.getX() + ":" + chessPoint.getY() + "=" + chessPoint.getNowPlay());
	}

	public void UnmakeMove(ChessPoint chessPoint, int depth) {
		if (chessStack.isEmpty()) {
			System.out.println("预测堆栈为空" + chessStack.size());
			return;
		}
		chessStack.pop();
		forecastChessboard[chessPoint.getX()][chessPoint.getY()] = 0;
		
//		for(int o = 0; o <(maxDepth - depth)*2; o++)
//			System.out.print(" ");
//		System.out.println(depth + "去子：" + chessPoint.getX() + ":" + chessPoint.getY() + "=" + chessPoint.getNowPlay());
	}
}
